<script lang="jsx">
import {
  reactive,
  defineComponent,
  h,
  watch,
  ref,
  nextTick,
  onMounted,
} from "vue";
import { isEmpty } from "@/components/utils/index.js";
import { ElTableColumn, ElTable, ElPagination } from "element-plus";
import Sortable from 'sortablejs'; // 拖拽排序插件

/**
 * 自执行父组件的getList方法(若存在getList)
 * getList函数为promise自动增加loading
 * getList返回值格式：return {rows:[],total:100}
 * 固定表头滚动
 * 插槽：top、 topLeft、topRight、bottom、bottomLeft、bottomRight
 * 表格勾选项支持 v-model:selected="data.selectRows"
 * */

export default defineComponent({
  name: "cTable",
  inheritAttrs: false, // 取消透传 Attributes (v-on监听器也会被继承)
  props: {
    columns: {
      // 表格列的配置描述,也就是el-table-column (若数据为空会使用 '-' 替代)
      default: () => [],
      required: true, // 是否必填
      type: Array,
    },
    rowKey: {
      // 传入selected后，row-key必传
      type: [Number, String],
    },
    selected: {
      // 表格 勾选项  (TODO: 显示多选后，row-key必传)
      // default: () => [],
      type: Array,
    },
    pagProps: {
      // 分页props
      default: () => {},
      type: Object,
    },
    showIndex: {
      // 是否显示序号
      default: false,
      type: Boolean,
    },
    selectionProps: {
      // 多选 table-col-props (仅对 type=selection 的列有效)
      default: () => {},
      type: Object,
    },
    isRowClick: Boolean, // 为true默认开启行点击,点击改变selectRows
  },
  setup(props, e) {
    const { slots, attrs, emit, expose } = e;
    const { onGetList } = attrs;
    const eleTable = ref(null); // ref elTable
    const data = reactive({
      loading: false,
      selectRows: [], //
      tableData: [], // 表格数据
      currentPage: 1, // 当前页
      pageSize: 10, // 每页显示条目个数
      total: 0, // 总条数
    });

    onMounted(() => {
      if (
        process.env.NODE_ENV === "development" &&
        props.selected &&
        !props.rowKey
      ) {
        console.error("传入selected后，rowKey必传");
      }

      rowDrop() // 表格行拖动排序
    });

    watch(
      () => props.selected,
      (list) => {
        if (!list || !Array.isArray(list)) return;
        data.selectRows = list;
      },
      {
        immediate: true,
      }
    );

    /**
     * 表格行拖动排序
     * */
    function rowDrop() {
      // 阻止默认行为
      document.body.ondrop = function (event) {
        event.preventDefault();
        event.stopPropagation();
      };
      console.log(eleTable,"eleTable");
      const tbody = eleTable.value.$el.querySelector(".el-table__body-wrapper tbody");
      const options = {
        ghostClass: "sortable-ghost",  // drop placeholder的css类名
        chosenClass: "sortable-chosen",  // 被选中项的css 类名
        dragClass: "sortable-drag",  // 正在被拖拽中的css类名
        onEnd: ({ newIndex, oldIndex }) => {
          if (newIndex === oldIndex) return;
          const newData = [...data.tableData];
          // 将oldIndex项删除,移动到newIndex
          newData.splice(newIndex, 0, newData.splice(oldIndex, 1)[0]);
          data.tableData = [];
          nextTick(() => {
            data.tableData = newData;
            emit(
              "dragEnd",
              newData.map((item, i) => ({
                ...item,
                sort: indexMethod(i),
              }))
            );
          });
        },
      };
      Sortable.create(tbody, options);
    }

    /**
     * 当勾选项发生变化时会触发该事件
     * @param {Array} selection
     * @param {Boolean} isSelect
     * */
    function selectTabRows(selection, isSelect) {
      const rowKey = props.rowKey;
      if (isSelect) {
        // 选中
        selection.forEach((item) => {
          const idx = data.selectRows.findIndex(
            (it) => item[rowKey] === it[rowKey]
          );
          if (idx !== -1) {
            // 删除已存在的项
            data.selectRows.splice(idx, 1);
          }
        });
        data.selectRows.push(...selection);
        emit("update:selected", data.selectRows);
        return;
      }
      // 取消选中
      const ids = selection.map((item) => item[rowKey]);
      data.selectRows = data.selectRows.filter(
        (item) => !ids.includes(item[rowKey])
      );
      emit("update:selected", data.selectRows);
    }

    /**
     * 全选
     * @param {Array} selection
     * */
    function selectAllChange(selection) {
      const isSelect = !!selection.length;
      let newData = selection;
      if (!isSelect) {
        newData = data.tableData;
      }
      selectTabRows(newData, isSelect);
    }

    /**
     * 单选
     * @param {array} selection
     * @param {object} row
     * */
    function handleSelect(selection, row) {
      const rowKey = props.rowKey;
      const isSelect = selection.some((item) => item[rowKey] === row[rowKey]);
      selectTabRows([row], isSelect);
    }

    /**
     * page-size 改变时触发
     * */
    function sizeChange(size) {
      data.pageSize = size;
      getData();
    }

    /**
     * current-page 改变时触发
     * */
    function currentChange(current) {
      data.currentPage = current;
      getData();
    }

    /**
     * table序号
     * */
    function indexMethod(index) {
      return (data.currentPage - 1) * data.pageSize + (index + 1);
    }

    /**
     * 判断getList是否为promise,是：为table加上loading
     * */
    async function dispatch(res) {
      let result = res;
      if (res instanceof Promise) {
        data.loading = true;
        result = await res;
        data.tableData = result.rows || [];
        data.total = result.total || 0;
        // selection 是否开启多选
        setTableCheck(); // 根据selectRows 回显选中
        data.loading = false;
        return;
      }
      const start = (data.currentPage - 1) * data.pageSize;
      const rows = result.rows || [];
      data.tableData = rows.slice(start, start + data.pageSize); // 数据超过pageSize，则截取
      data.total = result.total || 0;
      setTableCheck(); // 根据selectRows 回显选中
    }

    /**
     * 根据selectRows 回显选中
     * */
    function setTableCheck() {
      const tableData = data.tableData;
      if (tableData.length === 0 || data.selectRows.length === 0) return;
      const rowKey = props.rowKey;
      const ids = data.selectRows.map((i) => i[rowKey]);
      tableData.forEach((item) => {
        if (ids.includes(item[rowKey])) {
          nextTick(() => {
            eleTable.value.toggleRowSelection(item, true);
          });
        }
      });
    }

    /**
     * 执行外部getList获取表格数据
     * */
    function getData() {
      if (!onGetList) return;
      const res = onGetList({
        currentPage: data.currentPage,
        pageSize: data.pageSize,
      }); // 执行getList获取tableData

      dispatch(res); // 判断函数是否为promise，并且加上loading效果
    }
    getData(); // 执行getList

    /**
     * 刷新表格 (外部ref调用)
     * @param {Object} params
     * @param {Number} params.currentPage 当前页
     * @param {Number} params.pageSize 每页显示多少条数据
     * @param {Number} params.quantity 删除的数量
     * */
    function reload(params) {
      // 修改页数后执行getList
      const { currentPage, pageSize, quantity } = params;
      if (currentPage) {
        data.currentPage = currentPage;
      }
      if (pageSize) {
        data.pageSize = pageSize;
      }
      if (
        quantity === data.tableData.length &&
        !currentPage &&
        data.currentPage > 1
      ) {
        data.currentPage -= 1;
      }
      getData(); // 刷新
    }

    expose({ reload });

    /**
     * 渲染Columns
     * @param {Array} columns
     * @returns {Array} VNode
     * */
    function renderColumns(columns) {
      if (columns && columns.length) {
        return columns.map((item) => {
          const { prop, property, columns, customRender, customHeader } = item;
          const formatter = (row) => {
            // row, column, cellValue, index
            if (prop || property) {
              // 比如自定义操作栏 不需要 formatter
              return isEmpty(row[prop || property]); // value为空默认给 '-'
            }
          };

          const columnProps = {
            showOverflowTooltip: true, // 默认当内容过长被隐藏时显示 tooltip,TODO 暂未考虑横杠方式
            align: "center", // 默认居住
            formatter,
            ...item, // 上部分可通过item外部传进来覆盖
          };
          const content = {};
          if (columns?.length || customRender) {
            // 自定义列
            // customRender和renderColumns（渲染多级表头不能同时存在）,因为都是插槽default
            content.default = (scope) => {
              //自定义列的内容，参数为 { row, column, $index }
              if (columns?.length) {
                return renderColumns(item.columns);
              }
              if (customRender) {
                return customRender(scope);
              }
            };
          }
          if (customHeader) {
            // 自定义头
            content.header = (scope) => customHeader(scope);
          }
          return h(ElTableColumn, columnProps, content);
          /*return (
            <el-table-column {...columnProps}>{{ ...content }}</el-table-column>
          );*/
        });
      }

      return slots;
    }

    /** 表格行点击
     * @param row {Object} 行
     * @param column {Object}
     * @param event {Object}
     * */
    function rowClick(row, column, event) {
      const selectable = eleTable.value.store.states.selectable.value; // 外部没传该函数为undefined
      const rowKey = props.rowKey;
      if (!rowKey) {
        throw new Error("isRowClick为true,rowKey必传");
      }
      const idx = data.tableData.findIndex(
        (item) => item[rowKey] === row[rowKey]
      );
      if (!props.isRowClick || (selectable && !selectable(row, idx))) {
        // isRowClick为false 或者 这一列是禁用的
        return;
      }
      // 是否已存在
      const exist = data.selectRows.some(
        (item) => item[rowKey] === row[rowKey]
      );
      selectTabRows([row], !exist);
      eleTable.value.toggleRowSelection(row, !exist); // 切换某一行的选中状态
    }

    /**
     * 渲染底部区域 (bottom)
     * @return {JSX.Element | undefined}
     * */
    function renderBottom() {
      const { bottomLeft = () => {}, bottom = () => {}, bottomRight } = slots;
      const _bottomLeft = bottomLeft();
      let _bottomRight = null;
      const _bottom = bottom();

      if (data.total) {
        _bottomRight = (
          <ElPagination
            currentPage={data.currentPage}
            onUpdate:currentPage={currentChange}
            pageSizes={[10, 20, 50, 100]}
            pageSize={data.pageSize}
            onUpdate:pageSize={sizeChange}
            total={data.total}
            background
            layout="total, sizes, prev, pager, next, jumper"
            {...props.pagProps}
          />
        );
      } else if (bottomRight) {
        _bottomRight = bottomRight();
      }

      if (_bottomLeft || _bottomRight) {
        return (
          <div class="c-table-footer">
            {_bottom ? _bottom : null}

            {_bottomLeft ? (
              <div className="bottom-left">{_bottomLeft}</div>
            ) : null}

            {_bottomRight ? (
              <div className="bottom-right">{_bottomRight}</div>
            ) : null}
          </div>
        );
      }
    }

    /**
     * 渲染顶部区域 (top)
     * @return {JSX.Element | undefined}
     * */
    function renderTop() {
      const { topLeft = () => {}, top = () => {}, topRight = () => {} } = slots;
      const _topLeft = topLeft();
      const _topRight = topRight();
      const _top = top();
      if (_top) {
        return _top;
      }
      if (_topLeft || _topRight) {
        return (
          <div class="c-table-top">
            {_topLeft ? <div className="top-left">{_topLeft}</div> : null}
            {_topRight ? <div className="top-right">{_topRight}</div> : null}
          </div>
        );
      }
    }

    return () => (
      <div {...{ class: "c-table" }}>
        {renderTop()}
        <ElTable
          ref={eleTable}
          class={{ "table-row-pointer": props.isRowClick }}
          v-loading={data.loading}
          element-loading-text="加载中..."
          {...{
            border: true,
            data: data.tableData,
            onSelect: handleSelect,
            onSelectAll: selectAllChange,
            onRowClick: rowClick,
            ...attrs,
          }}
        >
          {props.selected ? (
            <el-table-column
              align="center"
              type="selection"
              width="55"
              {...props.selectionProps}
            ></el-table-column>
          ) : null}

          {props.showIndex ? (
            <el-table-column
              type="index"
              index={indexMethod}
              label="序号"
              width="70px"
              align="center"
            ></el-table-column>
          ) : null}
          {renderColumns(props.columns)}
        </ElTable>

        {renderBottom()}
      </div>
    );
  },
});
</script>

<style lang="less" scoped>
.c-table {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  .el-table {
    width: 100%;
    flex: 1;
  }
  .c-table-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 10px;
  }
  .c-table-top {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 10px;
  }
}

.table-row-pointer {
  :deep(.el-table__body-wrapper) {
    .el-table__body {
      .el-table__row {
        cursor: pointer;
      }
    }
  }
}
</style>
